package com.swyc.osschat.Common.Util.Tree;

import com.swyc.osschat.Common.Util.Object.StringUtil;
import org.jboss.logging.Logger;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yanyipeng.ykw@foxmail.com
 * @date 2019/3/20 14:14
 */
public class TreeUtil {

    private static Logger logger = Logger.getLogger(TreeUtil.class);

    private static final String DEFAULT_ID_SIGN = "id";

    private static final String DEFAULT_PARENT_ID_SIGN = "parentId";

    public static <T, ID extends Serializable> List<Tree<T, ID>> treeList(List<T> list){
        return treeList(list,DEFAULT_ID_SIGN,DEFAULT_PARENT_ID_SIGN);
    }

    public static <T, ID extends Serializable> List<Tree<T, ID>> treeList(List<T> list,String idSign,String parentSign) {
        List<Tree<T,ID>> topTree = new ArrayList<>();
        if(list != null && !list.isEmpty()){
            Class<?> clz = list.get(0).getClass();
            Map<ID,List<Tree<T,ID>>> childMap = new HashMap<>(list.size());
            list.forEach(t -> {
                ID id = getSignVal(clz,t, StringUtil.nullToStringDefault(idSign,DEFAULT_ID_SIGN));
                ID parentId = getSignVal(clz,t, StringUtil.nullToStringDefault(parentSign,DEFAULT_PARENT_ID_SIGN));
                if (id != null){
                    Tree<T,ID> tree = new Tree<>();
                    tree.setId(id);
                    tree.setMine(t);
                    if(parentId == null){
                        topTree.add(tree);
                    }else {
                        tree.setParentId(parentId);
                        List<Tree<T, ID>> trees = childMap.get(parentId);
                        if (trees == null){
                            trees = new ArrayList<>();
                        }
                        trees.add(tree);
                        childMap.put(parentId,trees);
                    }
                }else {
                    logger.error("获取ID失败.");
                }
            });
            recursionMap(childMap,topTree);
        }
        return topTree;
    }

    private static <T,ID extends Serializable> void recursionMap(Map<ID,List<Tree<T,ID>>> childMap,List<Tree<T,ID>> topTree){
        if(childMap != null && childMap.size() > 0 && topTree != null && topTree.size() > 0){
            topTree.forEach(tree ->{
                List<Tree<T, ID>> trees = childMap.get(tree.getId());
                if (trees != null){
                    tree.setChild(trees);
                    childMap.remove(tree.getId());
                    recursionMap(childMap,trees);
                }
            });
        }
    }

    private static <T extends Object,ID extends Serializable> ID getSignVal(Class<?> clz,T source,String fieldName){
        ID id = null;
        if (source != null && StringUtil.isNotEmpty(fieldName)){
            try {
                Field field = clz.getDeclaredField(fieldName);
                field.setAccessible(true);
                Object val = field.get(source);
                if(val != null){
                    id = (ID) val;
                }
            } catch (NoSuchFieldException e) {
                Class<?> superclass = clz.getSuperclass();
                return getSignVal(superclass,source,fieldName);
            } catch (IllegalAccessException e) {
                logger.error("获取字段值失败[fieldName]:"+fieldName,e);
            }
        }
        return id;
    }

    private TreeUtil() {
    }

}
